# -*- coding: utf8 -*-
import sys, select, socket, threading, os, re,pg
from math import sqrt

ip = sys.argv[1]
tcp_port = int(sys.argv[2])
nodes_f = sys.argv[3]
#archi=open('datos'+ip+str(tcp_port)+'.txt','w')


class MsgDecoder():

	#EXTRAE LOS CAMPOS DE UN MENSAJE. TIENE UN METODO POR CADA TIPO DE MENSAJE

	def __init__(self):
		pass

	def decode(self,msg):
		fields = msg.split('|')
		exec('d = self.decode'+fields[0]+'(fields)')
		return d

	def decode100(self,fields):
		return {'code':fields[0],'id':fields[1]}

	def decode101(self,fields):
		return self.decode100(fields)	

	def decode102(self,fields):
		return {'code':fields[0],'id':fields[1]}
		

	def decode103(self,fields):
		return {'code':fields[0],'node_id':fields[1],'codigo':fields[2],'query':fields[3],'ttl':fields[4],'duenio':fields[5],'envio':fields[6]}

	def decode104(self,fields):
		return {'code':fields[0],'node_id':fields[1],'query':fields[2],'imagenes':fields[3]}

	def decode105(self,fields):
		return {'code':fields[0],'node_id':fields[1]}

	def decode106(self,fields):
		return {'code':fields[0],'node_id':fields[1],'mensaje':fields[2]}	

	def decode200(self,fields):
		return {'code':fields[0],'name':fields[1], 'address':fields[2]}

	def decode201(self,fields):
		return {'code':fields[0],'id':fields[1]}	
		
	def decode202(self,fields):
		return {'code':fields[0],'id':fields[1],'codigo':fields[2], 'query':fields[3], 'ttl':fields[4] }

	def decode203(self,fields):
		return {'code':fields[0],'users':fields[1]}	

	def decode204(self,fields):
		return self.decode201(fields)
	
	def decode210(self,fields):
		return {'code':fields[0], 'id':fields[1],'im':fields[2]}
			
	def decode206(self,fields):
		return self.decode106(fields)
		
	def decode212(self,fields):
		return {'code':fields[0],'id':fields[1],'im':fields[2]}

class Client_Udp():
	
	def __init__(self,host,port,bytess):
		self.ip = host
		self.port = port
		self.s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # Declaro Socket TCP
		
		self.bytess = bytess
		
	def Enviar(self,mensaje):
		self.s.sendto(mensaje,(self.ip,int(self.port)))
		
	def Recibir(self):
		data = self.s.recvfrom(self.bytess)
		print data[0]
	
class Server_Udp():
	
	def __init__(self,host,port,maxpedidos,bytess):
		'''self.address=""
		self.client=""
		
		
		self.final_data = ""
		self.bytess = bytess
		print "la direccion UDP es: ",host, port
		self.s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
		self.s.bind(('',port))
		'''
		self.data=""
		self.s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)    # Create Datagram Socket (UDP)
		self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # Make Socket Reusable
		self.s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) # Allow incoming broadcasts
		self.s.setblocking(False) # Set socket to non-blocking mode
		self.s.bind((host, port)) #Accept Connections on port
		print "Accepting connections on port",(port)
		
			
	def Recibir_datos(self):

		print "Comienzo Lectura UDP"
		
		def getLine():
			i,o,e = select.select([sys.stdin],[],[],0.0001)
			for self.s in i:
				if self.s == sys.stdin:
					input = sys.stdin.readline()
					return input
			return False
			
		giro = True
		esperando = 0
		while giro:
			try:
				message, address = self.s.recvfrom(8192)
				if message:
					print address, "> ", message
					self.data+=message
			except:
				esperando+=1
				if (esperando >30000):
					giro = False
				
		 
			input = getLine();
			
			if(input != False):
				giro = False #s.sendto(input, address)
		print "Fin de Lectura UDP "
		
	
	def Respuesta(self):
		
		
		self.s.sendto(self.data,self.address)
	
class Neighboor():

	#CLASE DE ADYACENTE O VECINO, ES EL TIPO DE OBJETO QUE CONTIENE LA LISTA DE VECINOS DEL SUPERNODO

	def __init__(self,address,connection):
		self.address = address
		self.id = self.address[0]+':'+str(self.address[1])
		self.connection = connection
		
	def send(self,data):
		self.connection.send(data)

	def recv(self):
		return self.connection.recv()
	
	def show(self):
		return self.id

	def close(self):
		self.connection.close()
	
	def result(self):
		self.connection.result()

class User(Neighboor):

	#OBJETO QUE REPRESENTA A UN USUARIO CONECTADO AL SUPERNODO

	count = 1000

	def __init__(self,name,address,connection):
		Neighboor.__init__(self,address,connection)
		self.id = str(User.count)
		User.count += 1
		self.name = name
		#self.interest = None

	def show(self):
		return self.id+' '+self.info()

	def info(self):
		return self.name+' '+self.address[0]+':'+str(self.address[1])	

class TCP_Connection(threading.Thread):

	def __init__(self,socket,node):
			threading.Thread.__init__(self)
			self.socket = socket
			self.node = node
			self.results = {}
			self.flag = 1

			
	def trigger(self,data):
		#DISPARA ACCION SEGUN MENSAJE RECIBIDO
		fields = self.node.decode(data)
		if fields['code'] == '100':
			#AGREGA AL VECINO (COLOCANDOSE A SI MISMO) Y LE ENVIA RESPUESTA
			ip,port = fields['id'].split(':')
			self.node.lock.acquire()
			self.node.add_neigh((ip,int(port)),self)
			self.node.lock.release()
			print data
			self.send('101|'+self.node.address[0]+':'+str(self.node.address[1])+'||')
		elif fields['code'] == '101':
			print data 
		elif fields['code'] == '102':
			#LE ENVIA RESPUESTA AL ADYACENTE Y LO QUITA DE LA LISTA
			#LUEGO FINALIZA EL THREAD
			print data
			self.send('106|'+node.address[0]+':'+str(self.node.address[1])+'|'+'Conexión Cerrada ||')
			self.node.lock.acquire()
			self.node.remove_neigh(fields['id'])
			self.node.lock.release()			
			self.close()
		elif fields['code'] == '103':
			print data
			self.node.lock.acquire()
			clave = fields['node_id']+fields['codigo'] 
			if self.node.in_process(clave):
				print " Ya esta siendo Procesado" 
				self.node.lock.release()
				print " release funcionando"
				# Si es no bloqueante lo tiro, si no un 104 vacio
				#self.send('104|'+fields['node_id']+'|'+fields['codigo']+'|'+fields['query']+'|'+fields['ttl']+'|/||')
			else:
				print " Lo agrego porque nunca me llego una consulta " 
				self.node.processing.append(fields['node_id']+fields['codigo'])
				self.node.lock.release()
				#INICIO EL THREAD QUE SE ENCARGA DE LA RECOLECCIÓN DE LOS RESULTADOS
				FinderNoOriginal(self, node, fields['node_id'], fields['codigo'], fields['query'], fields['ttl'],fields['duenio'],fields['envio'],2,data).start()
				#Results_Collector103(self,node,fields['node_id'],fields['query'],fields['ttl']).start()
		elif fields['code'] == '104':
			print data
			#ALMACENO EL RESULTADO OBTENIDO DE OTRO SUPER NODO
			if (fields['imagenes']=='/'):
				self.results[fields['node_id']] = 'nada'
			else:
				self.results[fields['node_id']] = fields['imagenes']
				
		elif fields['code'] == '105':
			print " ------"
			print data
			
			self.node.lock.acquire()
			#SI ESTA EN PROCESADOS LO QUITO Y REENVIO A LOS ADYACENTES
			if self.node.in_process(fields['node_id']):
				self.node.remove_in_process(fields['node_id'])
				for neigh_id,neigh in self.node.neighs.iteritems():
					neigh.send(data+'||')			
			self.node.lock.release()
		elif fields['code'] == '106':
			print data
			#CIERRA EL THREAD CUANDO EL EXTREMO LE RESPONDE LA DESCONEXION
			self.close()
		elif fields['code'] == '200':
			print data
			#AGREGA AL USUARIO Y LE ENVIA EL ID GENERADO
			ip,port = fields['address'].split(':')			
			self.node.lock.acquire()
			user = self.node.add_user(fields['name'],(ip,int(port)),self)
			self.node.lock.release()
			self.send('201|'+user.id+'||')
		elif fields['code'] == '202':
			#LE RETORNA LAS IMAGENES RELEVANTES AL QUERY DEL USUARIO
			#AGREGO A LA LISTA DE LOS QUE SE ESTAN PROCESANDO -> NO PISAR COSAS
			print data
			#archi=open('datos.txt','a')
			#archi.write('Llega mensaje'+data+'\n')
			#archi.close()
			self.node.lock.acquire()
			clave = fields['id']+fields['codigo']
			nodo_duenio = self.node.address[0]+':'+str(self.node.address[1])
			nodo_envio = nodo_duenio
			self.node.processing.append(clave)
			self.node.lock.release()
			#self.node.processing.append(self.node.address[0]+':'+str(self.node.address[1])+fields['id'])
			
			
			#INICIO EL THREAD QUE SE ENCARGA DE LA RECOLECCION DE QUERYS RELEVANTES
			# En el Run voy a armar el mensaje 103 con ip:puerto del SN'original'
			
			
			FinderPictures(self, node, fields['id'], fields['codigo'], fields['query'], fields['ttl'], nodo_duenio, nodo_envio ,1).start()
			
		elif fields['code'] == '204':
			#QUITA AL USUARIO DE LA LISTA Y LE ENVIA UNA RESPUESTA
			print data
			self.node.lock.acquire()
			user = self.node.remove_user(fields['id'])
			self.node.lock.release()
			self.send('206|Conexion Cerrada con Supernodo||')
			self.close()
		elif fields['code'] == '210':
			# Alta de imagenes
			print data
			self.node.imagenes.append({'id':fields['id'], 'imagen':fields['im']})
			self.send('211|'+fields['im']+'||')
	def send(self,data):
		#log.write('to '+str(self.socket.getpeername())+': '+data+'\n')
		#print 'to '+str(self.socket.getpeername())+': '+data	
		self.socket.send(data)

	def close(self):
		self.flag = 0
	
	def run(self):
		print "Entramos al Run"
		while self.flag:
			data = ''
			while not(data[-2:]=='||'):
				data += self.socket.recv(1024)
			
			#log.write('from '+str(self.socket.getpeername())+': '+data+'\n')
			#print 'from '+str(self.socket.getpeername())+': '+data+'\n'
			#CONTROL POR SI HAY VARIOS MENSAJES EN BUFFER
			for msg in data.split('||')[:-1]:
				self.trigger(msg)
		self.socket.close()

	
class FinderPictures(threading.Thread):

	def __init__(self,connection,supernodo,nodo_hoja_id,codigo,query,ttl, nodo_duenio, nodo_envio, tipo):
		threading.Thread.__init__(self)
		self.connection = connection
		self.supernodo = supernodo
		self.id_nodo_hoja = nodo_hoja_id
		self.query = query
		self.ttl = ttl
		self.tipo = tipo
		self.codigo = codigo
		self.nodo_duenio = nodo_duenio
		self.nodo_envio = nodo_envio
		self.resultados = ""
		

	def relevant_pictures(self,users,neighs,queryx,data,uid,codigo,ttl,nodo_duenio):
		#RETORNA IMAGENES RELEVANTE AL QUERY DEL USUARIO
		#BASANDOSE EN LOCAL PICTURES Y LAS PICTURES DE LOS NODOS VECINOS!
		a = self.local_relevant_pictures(self.supernodo, self.query)
		self.external_relevant_pictures(neighs,data,uid,codigo,ttl,nodo_duenio)
		return a
	def local_relevant_pictures(self,supernodo,query):
        #ACA DEVOLVERIA LaS IMAGENES RELEVANTES AL QUERY DEL USUARIO
        #RECORRE TODOS LAS IMAGENES DEL SUPERNODO
		result = ""
		for foto in supernodo.imagenes:
		    # RECUPERO SOLO LOS IGUALES
		    # SOLO POR AHORA
			var = foto['imagen']
			
			if (var == query):
				#_input ('uno igual')
				result+= foto['id']+'/'+foto['imagen']+'@'
                #print "local "+result             
		return result
        
        
	def external_relevant_pictures(self,neighs,msg,id_nodo_hoja,codigo,ttl, nodo_duenio):
		#ACA EL SUPERNODO BUSCARA LAS IMAGENES RELEVANTES EN LOS OTROS SUPERNODOS
		l_pictures = ''
		#SI EL TTL ES MAYOR A CERO PUEDO BUSCAR EN ADYACENTES, SINO CORTO
		if int(self.ttl) > 0:
			self.ttl = int(self.ttl) - 1
			# Creo el SOcket UDP para recibir las peticiones 
			# Me quedo con la IP, y uso un puerto efimero
			msg = '103|'+self.id_nodo_hoja+'|'+str(self.codigo)+'|'+self.query+'|'+str(self.ttl)+'|'+ self.nodo_duenio +'|'+self.nodo_envio+'||'
			
			for neigh_id,neigh in neighs.iteritems():
				print "External: Estamos mandando a otro vecino", 
				#archi=open('datos.txt','a')
				#archi.write('External: Estamos mandando a otro vecino'+neigh_id+'\n')
				#archi.close()
				print str (neigh_id)
				print str (nodo_duenio)
				if (self.nodo_duenio != neigh_id):
					if (self.nodo_envio != neigh_id):
					
						neigh.send(msg)
			
			#Recibo los datos
			self.supernodo.udp.Recibir_datos()
			
			print " SALIMOS DE TODO-> ", self.supernodo.udp.data
		#return l_pictures
			
	def copy_lists(self):
		#SE ARMA SU LISTA DE USUARIOS Y VECINOS POR EL TEMA DEL LOCKEO
		self.supernodo.lock.acquire()
		users = self.supernodo.users.copy()
		neighs = self.supernodo.neighs.copy()
		self.supernodo.lock.release()
		return (users,neighs)

	def run(self):
		# Le asigno un servidor UDP al Supernodo, para que pueda recibir las respuestas de los otros 
		#Supernodos
		ip, puerto = self.nodo_duenio.split(':')
		puerto = int (puerto) + 100
		self.supernodo.udp = Server_Udp(ip,puerto,10,512)
		
		#COLECTA VECINOS RELEVANTES PARA LUEGO PODER MANDAR LA QUERY POR ELLOS
		# eSTO SE USA PARA EXTERNAL RELEVANT PICTURES 
		#print "Tipo: ", self.tipo
		users,neighs = self.copy_lists()
		# Creo el mensaje 103 que tiene todos los datos + my IP:PUERTO 
		msg = '103|'+self.id_nodo_hoja+'|'+str(self.codigo)+'|'+self.query+'|'+str((self.ttl))+'|'+ self.nodo_duenio +'||'
		
		l_pictures = self.relevant_pictures(users, neighs, self.query, msg, self.id_nodo_hoja,self.codigo,self.ttl,self.nodo_duenio)
		l_pictures+= self.resultados
		print " Termino el proceso "
		print l_pictures
		raw_input('')
		#ENVIA LA RESPUESTA
		#print"llegahastaaca"
		# Veremos cuando hace lo que sigue" 
		if (self.tipo == 1):
			self.connection.socket.send('203|'+l_pictures+'||')
		else:
			print "Esto no va mas" 
			#self.connection.socket.send('104|'+self.id_nodo_hoja+'|'+self.query+'|'+l_pictures+'||')
		#self.connection.socket.send('203|'+l_pictures+'||')
		#self.connection.send('203| argo||')
		#print l_picture
		
			
		#AVISA A TODOS LOS ADYACENTES QUE LIBEREN EL QUERY DE LISTA DE PROCESADOS
		for neigh_id,neigh in neighs.iteritems():
				neigh.send('105|'+self.id_nodo_hoja+'||')


class FinderNoOriginal(threading.Thread):

	def __init__(self,connection,supernodo,nodo_hoja_id,codigo,query,ttl, nodo_duenio, nodo_envio,tipo,msg):
		threading.Thread.__init__(self)
		self.connection = connection
		self.supernodo = supernodo
		self.id_nodo_hoja = nodo_hoja_id
		self.query = query
		self.ttl = ttl
		self.tipo = tipo
		self.codigo = codigo
		self.nodo_duenio = nodo_duenio
		self.nodo_envio = nodo_envio
		self.msg = msg

	def relevant_pictures(self,users,neighs,queryx,data,uid,codigo,ttl,nodo_duenio):
		#RETORNA IMAGENES RELEVANTE AL QUERY DEL USUARIO
		#BASANDOSE EN LOCAL PICTURES Y LAS PICTURES DE LOS NODOS VECINOS!
		return self.local_relevant_pictures(self.supernodo, self.query) + self.external_relevant_pictures(neighs,data,uid,codigo,ttl,nodo_duenio)

	def local_relevant_pictures(self,supernodo,query):
        #ACA DEVOLVERIA LaS IMAGENES RELEVANTES AL QUERY DEL USUARIO
        #RECORRE TODOS LAS IMAGENES DEL SUPERNODO
		result = ""
		for foto in supernodo.imagenes:
		    # RECUPERO SOLO LOS IGUALES
		    # SOLO POR AHORA
			var = foto['imagen']
			
			if (var == query):
				#_input ('uno igual')
				result+= foto['id']+'/'+foto['imagen']+'@'
                #print "local "+result             
		return result
        
        
	def external_relevant_pictures(self,neighs,msg,ttl, nodo_duenio,nodo_envio):
		#ACA EL SUPERNODO BUSCARA LAS IMAGENES RELEVANTES EN LOS OTROS SUPERNODOS
		
		#SI EL TTL ES MAYOR A CERO PUEDO BUSCAR EN ADYACENTES, SINO CORTO
		if int(self.ttl) > 0:
			self.ttl = int(self.ttl) - 1
			# Creo el SOcket UDP para recibir las peticiones 
			# Me quedo con la IP, y uso un puerto efimero
			ip,puerto = self.nodo_duenio.split(':')
			
			
			for neigh_id,neigh in neighs.iteritems():
				print "External: Estamos mandando a otro vecino", 
				
				if (neigh_id != self.nodo_duenio):
					if (neigh_id != self.nodo_envio):
						print str (neigh_id)
						print str (nodo_duenio)
						mi = 'sos un zapallo '
						neigh.send(mi)
			
		
			
	def copy_lists(self):
		#SE ARMA SU LISTA DE USUARIOS Y VECINOS POR EL TEMA DEL LOCKEO
		self.supernodo.lock.acquire()
		users = self.supernodo.users.copy()
		neighs = self.supernodo.neighs.copy()
		self.supernodo.lock.release()
		return (users,neighs)

	def run(self):
		
		# PRIMERO RECUPERO LOS RESULTADOS LOCALES Y SE LOS MANDO AL SN ORIGINAL
		# CON LOCAL_RELEVANT PICTURES
		
		local_pictures = "soy vecino" +self.local_relevant_pictures(self.supernodo, self.query)
		
		
		''' Ahora intento mandar las locales que es lo que me corresponde al momento'''
		print "estoy mandando", local_pictures
		ip,puerto = self.nodo_duenio.split(':')
		puerto = int(puerto)+100
		udp = Client_Udp(ip,puerto,512)
		udp.Enviar(local_pictures)
			
		''' FIN DE MANDAR LAS LOCALES, AHORA COMIENZO POR LAS EXTERNAS '''
		
		#COLECTA VECINOS RELEVANTES PARA LUEGO PODER MANDAR LA QUERY POR ELLOS
		# Luego propago al resto de los vecinos  
		
		users,neighs = self.copy_lists()
		self.external_relevant_pictures(neighs, self.msg, self.ttl,self.nodo_duenio, self.nodo_envio)
		print " Termino el proceso "
		raw_input('')
		#Mi trabajo ha finalizado.
		
		

class Supernode():

	def __init__(self,address,nodes_file,ttl):
		self.address = address
		self.ttl = ttl
		self.imagenes = []
		# Socket basico de escucha 
		self.tcp = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
		self.tcp.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
		print "la direccion TCP es: ",self.address[0], self.address[1]
		self.tcp.bind(self.address)
		self.tcp.setblocking(0)
		self.tcp.listen(10)
		# Socket de recepcipn de mensajes
		self.udp = ""
		#Server_Udp(address[0],(int(address[1])+100),10,512)
		'''
		
		self.udp = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
		otro = int (self.address[1]) + 100
		print "la direccion UDP es : ",self.address[0], str(otro)
		self.udp.bind((self.address[0],otro))
		self.udp.setblocking(0)
		'''
		
		self.lock = threading.Lock()
		#ETAPA DE INICIALIZACIÓN
		self.flag = 1
		#SUPERNODOS ADYACENTES
		self.neighs = {}
		#NODOS HOJA CONECTADOS AL SUPERNODO
		self.users = {}
		#USUARIOS A LOS CUALES SE ESTA PROCESANDO
		self.processing = []
		#DECODIFICADOR DE MENSAJES
		self.decoder = MsgDecoder()
		#VERIFICO QUE ADYACENTES TENGO CONECTADOS
		for nodes in open(nodes_file,'r').readlines():
			ip, tcp_port = nodes[:-1].split(':')
			tcp_port = int(tcp_port)
			s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
			try:
				s.connect((ip,tcp_port))
				connection = TCP_Connection(s,self)
				connection.start()
				neigh = self.add_neigh(s.getpeername(),connection)
				neigh.send('100|'+self.address[0]+':'+str(self.address[1])+'||')
			except :
				print (ip,tcp_port)
				print 'No conectado'

	def connect_neigh(self,neigh_ip,neigh_port):
		s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
		try:
			s.connect((neigh_ip,neigh_port))
			connection = TCP_Connection(s,self)
			connection.start()
			neigh = self.add_neigh(s.getpeername(),connection)
			#neigh.send('100|'+self.address[0]+':'+str(self.address[1])+'||')
			s.send('100|'+self.address[0]+':'+str(self.address[1])+'||')
			
			print 'Nuevo adyacente agregado'
		except :
			print (neigh_ip,neigh_port)
			print 'No conectado'

	def add_neigh(self,address,connection):
		#INSTANCIA UN VECINO Y LO AGREGA A LA LISTA
		neigh = Neighboor(address,connection)
		self.neighs[neigh.id] = neigh
		return neigh
	
	def remove_neigh(self,neigh_id):
		neigh = self.neighs.pop(neigh_id)
		return neigh

	def add_user(self,name,address,connection):
		#INSTANCIA UN USUARIO Y LO AGREGA A LA LISTA
		user = User(name,address,connection)
		self.users[user.id] = user
		return user

	def remove_user(self,user_id):
		user = self.users.pop(user_id)

	def in_process(self,user_id):
		try:
			self.processing.index(user_id)
			return True
		except Exception,e:
			return False

	def remove_in_process(self,user_id):
		ind = self.processing.index(user_id)
		self.processing.pop(ind)


	def decode(self,data):
		#RETORNA UN DICCIONARIO CON LOS CAMPOS EXTRAÍDOS
		return self.decoder.decode(data)		

class Terminal(threading.Thread):

	#TERMINAL DE CONTROL DEL NODO

	def __init__(self,node):
		threading.Thread.__init__(self)
		self.node = node

	def run(self):
		print
		print '------------------------------------'
		print 'Comandos posibles:'
		print '------------------------------------'
		print '############## Operaciones SN - SN ####### '
		print '	Listar SuperNodos Vecino -> list neighs'
		print '	Remover SuperNodo Vecino ->  remove neigh <dir_ip>:<puerto>'
		print '	Agregar SuperNodo Vecino ->  add neigh <dir_ip>:<puerto>'
		print ' Recibir prueba x UDP	 ->  recv udp'
		print ' Enviar prueba x UDP	 ->  send udp <dir_ip>:<puerto>'
		
		print '############## Operaciones SN - N ####### '
		print '	Listar Nodos Hoja Conectados -> list leaf nodes'
		
		print '############## Operaciones SN ####### '
		print '	Listar imagenes -> list pictures'
		print '	Desconectarse -> disconnect'
		print '	Setear ttl -> ttl = <valor>'
		
		while self.node.flag:
			cmd = raw_input('>>')
			if (cmd == 'list pictures'):
				for i in self.node.imagenes:
					print i
			elif (cmd=='recv udp'):
				#data = node.udp.
				pass
				
				
			elif (cmd[0:8]=='send udp'):
				address = cmd[9:]
				
				ip, puerto = address.split(':')
				udp = Client_Udp(ip,puerto,512)
				udp.Enviar('hola')
					
			elif (cmd=='disconnect'):
				
				#SETEA EL FLAGO EN 0, LO QUE INTERRUMPE TODOS LOS LOOPS DE ESCUCHA
				self.node.flag = 0
			elif(cmd=='list neighs'):
				#MUESTRO MIS ADYACENTES
				print 'SuperNodos adyacentes\n'
				self.node.lock.acquire()
				for neigh_id,neigh in self.node.neighs.iteritems():
					print neigh.show()
				self.node.lock.release()
			elif(cmd=='list leaf nodes'):
				#MUESTRO USUARIOS
				print 'Usuarios\n'
				self.node.lock.acquire()
				for user_id,user in self.node.users.iteritems():
					print user.show()
				self.node.lock.release()
			elif not(re.match('ttl = (\d+)',cmd)==None):
				m = re.match('ttl = (\d+)',cmd)
				self.node.ttl = int(m.group(1))
				print 'TTL (Time to live) seteado a '+m.group(1)
			elif not(re.match('remove neigh ((\d{1,3}\.){3}\d{1,3}\:\d{1,4})',cmd)==None):
				m = re.match('remove neigh ((\d{1,3}\.){3}\d{1,3}\:\d{1,4})',cmd)
				try:
					neigh = self.node.remove_neigh(m.group(1))
					neigh.send('102|'+self.node.address[0]+':'+str(self.node.address[1])+'||')
					print 'Adyacente '+m.group(1)+' removido'
				except:
					print 'No existe un adyacente con el par ip:puerto indicado'				
			elif not(re.match('add neigh ((\d{1,3}\.){3}\d{1,3}\:\d{1,4})',cmd)==None):
				m = re.match('add neigh ((\d{1,3}\.){3}\d{1,3}\:\d{1,4})',cmd)
				if not(self.node.neighs.has_key(m.group(1))):				
					nip,nport = m.group(1).split(':')
					self.node.connect_neigh(nip,int(nport))
				else:
					print 'Ya se encuentra conectado al supernodo indicado'			
			else:
				print 'Comando incorrecto\n'

print '####################################################'
print '--SUPERNODO--'
print 'Red Peer to Peer - Taller Libre II - Universidad Nacional de Lujan 2012-2013'
print 'Petrocelli David Marcelo | L/N: 108779'
print '####################################################'
print
node = Supernode((ip,tcp_port),nodes_f,3)
#LOOP PRINCIPAL, EL SUPERNODO ESCUCHA EN TCP
#ABRE CONEXIONES Y LAS INICIA
Terminal(node).start()
while node.flag:
	try:
		s,address = node.tcp.accept()
		TCP_Connection(s,node).start()
	except Exception,e:
		pass
#CUANDO SALE DEL LOOP EMPIEZA A CERRAR CADA CONEXION CON SUS ADYACENTES
node.lock.acquire()
for neigh_id,neigh in node.neighs.iteritems():
	neigh.send('102|'+node.address[0]+':'+str(node.address[1])+'||')
	neigh.connection.join()
#for user_id,user in node.users.iteritems():
#	self.user.send('205|'+self.address[0]+':'+str(self.address[1])+'||')
node.lock.release()
node.tcp.close()
#log.close()

